﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;

namespace MarkovNameGeneratorApp
{
	/// <summary>
	/// Interaction logic for Window1.xaml
	/// </summary>
	public partial class Window1
	{
		private bool Stop
		{
			get
			{
				return !btnStop.IsEnabled;
			}
			set
			{
				btnStop.IsEnabled = !value;
			}
		}

		private readonly ObservableCollection<Name> _dataSource;
		private SCG.General.MarkovNameGenerator _generator;

		new class Language
		{
			public string LangName;
			public string FileName;
			public override string ToString()
			{
				return LangName;
			}
		}

		private readonly List<Language> _languages = new List<Language>
     	{
     		new Language {LangName = "German", FileName = @"..\..\german.dat"},
     		new Language {LangName = "English", FileName = @"..\..\english.dat"}
     	};

		public Window1()
		{
			InitializeComponent();
			cmbLanguageSelect.ItemsSource = _languages;
			cmbLanguageSelect.SelectedIndex = 0;

			_dataSource = new ObservableCollection<Name>();
			dgrdNameList.ItemsSource = _dataSource;
		}

		private void BtnGenerateClick(object sender, RoutedEventArgs e)
		{
			var toDelete = (from x in _dataSource where x.IsSelected == false select x).ToList();
			foreach (var x in toDelete)
				_dataSource.Remove(x);
			btnGenerate.IsEnabled = false;
			txtBegin.IsEnabled = false;
			txtEnd.IsEnabled = false;
			Stop = false;
			new Thread(SearchWords).Start();
			//new Thread(SearchWords).Start();
		}

		void SearchWords()
		{
			int foundRuns = 0;
			int totalRuns = 0;
			int totalRepeats = 0;
			string begin = "";
			string end = "";
			Dispatcher.Invoke
				(
					new Action(delegate
					{
						begin = txtBegin.Text.ToLower();
						end = txtEnd.Text.ToLower();
						Stop = false;
						progress.Minimum = 0;
						progress.Maximum = 20000;
						progress.SmallChange = 1;
						progress.LargeChange = 1;
						progress.Value = 0;
					})
				);

			while (foundRuns < 30 && totalRepeats < 5)
			{
				bool toStop = false;

				while (foundRuns < 30 && totalRuns != 20000)
				{
					Dispatcher.Invoke(new Action(delegate { toStop = Stop; }));
					if (toStop)
						break;
					string name = _generator.NextName;
					bool use;
					if (end != string.Empty && begin != string.Empty)
						use = name.ToLower().StartsWith(begin) && name.ToLower().EndsWith(end);
					else if (end == string.Empty && begin == string.Empty)
					{
						use = true;
					}
					else
						use = ((begin != string.Empty && name.ToLower().StartsWith(begin)) || (end != string.Empty && name.ToLower().EndsWith(end)));

					if (use)
					{
						Dispatcher.Invoke(new Action(() => _dataSource.Add(new Name {GeneratedValue = name})));
						foundRuns++;
					}
					int runs = totalRuns;
					Dispatcher.Invoke
						(
						new Action(delegate
						{
							txtLineStatus.Text = "Total runs: " + runs;
							progress.Value = runs;
						}
							));
					totalRuns++;
				}
				if(toStop)
					break;
				totalRuns = 0;
				totalRepeats++;
			}
			Dispatcher.Invoke(new Action(delegate
			{
				btnGenerate.IsEnabled = true;
				txtBegin.IsEnabled = true;
				txtEnd.IsEnabled = true;
				Stop = true;
				progress.Value = 0;
				txtLineStatus.Text = "Finished.";
			}));
		}

		private void BtnSaveClick(object sender, RoutedEventArgs e)
		{
			var toDelete = (from x in _dataSource where x.IsSelected == false select x).ToList();
			foreach (var x in toDelete)
				_dataSource.Remove(x);

			SaveFileDialog dlg = new SaveFileDialog();
			dlg.Title = "Append to file";
			dlg.Filter = "Text Files|*.txt";
			dlg.AddExtension = true;
			dlg.OverwritePrompt = false;
			if(dlg.ShowDialog() == true)
			{
				string txt = string.Join("\r\n", (from it in _dataSource select it.GeneratedValue).ToArray());
				File.AppendAllText(dlg.FileName, txt, Encoding.UTF8);
			}
		}

		private void BtnStopClick(object sender, RoutedEventArgs e)
		{
			Stop = true;
		}

		private void CmbLanguageSelectSelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			Language l = cmbLanguageSelect.SelectedItem as Language;
			if(l != null)
				SwitchLanguage(l);
		}

		void SwitchLanguage(Language lang)
		{
			IEnumerable<string> wordList = LoadWordList(lang.FileName);
			_generator = new SCG.General.MarkovNameGenerator(wordList, 3, 3);
		}

		private IEnumerable<string> LoadWordList(string filename)
		{
			BinaryFormatter bf = new BinaryFormatter();
			FileStream input = File.OpenRead(filename);
			return (List<string>)bf.Deserialize(input);
		}

		protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
		{
			if((from it in _dataSource where it.IsSelected select it).Count() > 0)
			{
				MessageBoxResult result = MessageBox.Show("List contains selected items, save them first?", "Caution", MessageBoxButton.YesNoCancel);
				if(result== MessageBoxResult.Yes)
				{
					Stop = true;
					BtnSaveClick(this, null);
				}
				else if(result == MessageBoxResult.Cancel)
				{
					e.Cancel = true;
					return;
				}
			}
			Stop = true;
			base.OnClosing(e);
		}
	}

	public class Name
	{
		public string GeneratedValue { get; set; }
		public bool IsSelected { get; set; }
	}
}
